package com.codejam.enums.demo.jackson;

import com.codejam.enums.demo.enums.IEnum;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import java.util.Arrays;
import lombok.SneakyThrows;

public class EnumJsonDeSerializer extends JsonDeserializer<IEnum> implements ContextualDeserializer {

    private Class<? extends IEnum> clazz;

    public EnumJsonDeSerializer() {
    }

    public EnumJsonDeSerializer(Class<? extends IEnum> clazz) {
        this.clazz = clazz;
    }

    @SneakyThrows
    @Override
    public IEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
        String param = jsonParser.getText();
        IEnum[] enumConstants = clazz.getEnumConstants();
        JsonStreamContext parsingContext = jsonParser.getParsingContext();
        IEnum iEnum = Arrays.stream(enumConstants)
            .filter(x -> {
                //x.toString(),取枚举的具体值，如：xxx.enums.share.DelFlagEnum 枚举里的“NOT_DELETE”
                //从而使得两种形式都能识别
                String enumCodeStr = x.toString();
                return enumCodeStr.equals(param) || param.equals(x.getCode() + "");
            })
            .findFirst()
            .orElse(null);
        if (null == iEnum) {
            String msg = String.format("枚举类型%s从%s未能转换成功", clazz.toString(), param);
            throw new Exception(msg);
        }
        return iEnum;
    }

    @Override
    public Class<?> handledType() {
        return IEnum.class;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
        throws JsonMappingException {
        JavaType type = property.getType();
        // 如果是容器，则返回容器内部枚举类型
        while (type.isContainerType()) {
            type = type.getContentType();
        }
        return new EnumJsonDeSerializer((Class<? extends IEnum>) type.getRawClass());
    }
}